package com.pen.sample.client.ui.stocks;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.pen.sample.client.model.ITradeRoutes;
import com.pen.sample.client.model.delegate.IResponder;
import com.pen.sample.client.model.delegate.IResult;
import com.pen.sample.client.model.objects.StockFood;

public class StocksNoble implements IStocksPeasant.INoble, IResponder, ClickHandler, KeyPressHandler
{
	private IStocksPeasant _peasant;
	private ITradeRoutes _tradeRoutes;
	private ArrayList<HandlerRegistration> _hrs;
	private ArrayList<String> _stocks;
	private Timer _updater;
	
	public StocksNoble( IStocksPeasant peasant, ITradeRoutes tradeRoutes )
	{
		_peasant = peasant;
		_peasant.getUpdateControl().setText( "" );
		_tradeRoutes = tradeRoutes;
		_hrs = new ArrayList<HandlerRegistration>();
		_stocks = new ArrayList<String>();
		addEventHandlers();
		
		_updater = new Timer()
		{	
			@Override
			public void run()
			{
				refreshStocks();
			}
		};
	}

	@Override
	public void kill()
	{
		if ( _hrs != null )
		{
			for ( int i = 0; i < _hrs.size(); i++ )
			{
				HandlerRegistration hr = _hrs.get( i );
				hr.removeHandler();
			}
			_hrs.clear();
		}
		if ( _stocks != null )
		{
			_stocks.clear();
			_stocks = null;
		}
		if ( _updater != null )
		{
			_updater.cancel();
			_updater = null;
		}
		_peasant = null;
		_tradeRoutes = null;
	}

	private void addEventHandlers()
	{
		_hrs.add( _peasant.getUserInput().addKeyPressHandler( this ) );
	}

	@Override
	public void onClick( ClickEvent e )
	{
		handleInput( _peasant.getUserInput().getText().toUpperCase().trim() );
	}

	@Override
	public void onKeyPress( KeyPressEvent e )
	{
		if ( e.getCharCode() == KeyCodes.KEY_ENTER )
			handleInput( _peasant.getUserInput().getText().toUpperCase().trim() );
	}

	@Override
	public void onResponse( IResult result )
	{
		if ( !result.isOk() )
		{
			//Perform some sort of logging or error handling
			return;
		}
		
		JsArray<StockFood> stocks = StockFood.getStockList( result.getResult().toString() );
		for ( int i = 0; i < stocks.length(); i++ )
		{
			StockFood stock = stocks.get( i );
			updateTable( stock );
		}
		_peasant.getUpdateControl().setText( "Last update: " + DateTimeFormat.getFormat( PredefinedFormat.DATE_TIME_MEDIUM ).format( new Date() ) );
		_updater.schedule( 5000 );
	}
	
	private void addStock( final String symbol )
	{
		_stocks.add( symbol );
		
		final FlexTable ft = _peasant.getStocksDisplay();
		int row = ft.getRowCount();
		ft.setText( row, 0, symbol );
		ft.setWidget( row, 2, new Label() );
		setTableStyles( row );

		// Add a button to remove this stock from the table.
		Button btnRemove = new Button( "x" );
		btnRemove.addStyleDependentName( "remove" );
		_hrs.add( btnRemove.addClickHandler( new ClickHandler()
		{
			public void onClick( ClickEvent event )
			{
				int idx = _stocks.indexOf( symbol );
				_stocks.remove( idx );
				ft.removeRow( idx + 1 );
			}
		} ) );
		ft.setWidget( row, 3, btnRemove );
	}
	
	private void handleInput( final String symbol )
	{
		final TextBox input = _peasant.getUserInput();
		input.setFocus( true );
		
		if ( !symbol.matches( "^[0-9A-Z\\.]{1,10}$" ) )
		{
			Window.alert( "\"" + symbol + "\" is not a valid symbol." );
			input.selectAll();
			return;
		}

		input.setText( "" );
		if ( _stocks.contains( symbol ) )
			return;

		addStock( symbol );
		
		refreshStocks();
	}
	
	private void refreshStocks()
	{
		_tradeRoutes.getStocks( _stocks, this );
	}

	private void setTableStyles( int row )
	{
		final FlexTable ft = _peasant.getStocksDisplay();
		ft.getCellFormatter().addStyleName( row, 1, "watchListNumericColumn" );
		ft.getCellFormatter().addStyleName( row, 2, "watchListNumericColumn" );
		ft.getCellFormatter().addStyleName( row, 3, "watchListRemoveColumn" );
	}
	
	private void updateTable( StockFood stock )
	{
		final String symbol = stock.getSymbol();
		if ( !_stocks.contains( symbol ) )
			return;
		
		int row = _stocks.indexOf( symbol ) + 1;
		String priceText = NumberFormat.getFormat( "#,##0.00" ).format( stock.getPrice() );
		NumberFormat changeFormat = NumberFormat.getFormat( "+#,##0.00;-#,##0.00" );
		String changeText = changeFormat.format( stock.getChange() );
		double cp = stock.getChangePercent();
		String changePercentText = changeFormat.format( cp );
		
		final FlexTable ft = _peasant.getStocksDisplay();
		ft.setText( row, 1, priceText );
		Label changeWidget = (Label) ft.getWidget( row, 2 );
		changeWidget.setText( changeText + " (" + changePercentText + "%)" );

		// Change the color of text in the Change field based on its value.
		String changeStyleName = "noChange";
		if ( cp < -0.1f )
			changeStyleName = "negativeChange";
		else if ( cp > 0.1f )
			changeStyleName = "positiveChange";

		changeWidget.setStyleName( changeStyleName );
	}
}
